use bytes::BytesMut;
use futures_util::{SinkExt, StreamExt};
use std::sync::Arc;
use tokio::{signal, task::JoinSet};
use tun_rs::DeviceBuilder;
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    let dev = DeviceBuilder::new()
        .name("tap1")
        .ipv4("10.0.0.1", 24, None)
        .layer(tun_rs::Layer::L2)
        .delete_driver(true)
        .mtu(1500)
        .build_async()
        .unwrap();
    let dev = Arc::new(dev);
    let ws_url = std::env::var("WS_URL").expect("WS_URL is not set");
    let (ws_stream, _) = tokio_tungstenite::connect_async(ws_url).await.unwrap();
    let (mut ws_sender, mut ws_receiver) = ws_stream.split();
    let mut buf = BytesMut::with_capacity(65536);
    let mut set = JoinSet::new();
    // send data to server
    let dev_reader = dev.clone();
    set.spawn(async move {
        loop {
            match dev_reader.recv(buf.as_mut()).await {
                Ok(len) => {
                    let pkg = buf[..len].to_vec().into();
                    if ws_sender
                        .send(tokio_tungstenite::tungstenite::Message::Binary(pkg))
                        .await
                        .is_err()
                    {
                        eprintln!("ws send err");
                        break;
                    }
                }
                Err(e) => {
                    println!("Error: {e}");
                    break;
                }
            }
        }
        Ok(())
    });
    // receive data from server
    let dev_sender = dev.clone();
    set.spawn(async move {
        while let Some(msg) = ws_receiver.next().await {
            match msg {
                Ok(tokio_tungstenite::tungstenite::Message::Binary(pkg)) => {
                    if let Err(e) = dev_sender.send(pkg.as_ref()).await {
                        eprintln!("Error: {e}");
                        break;
                    }
                }
                Ok(tokio_tungstenite::tungstenite::Message::Text(text)) => {
                    println!("Received: {text}");
                }
                Ok(_) => {}
                Err(e) => {
                    println!("Error: {e}");
                    break;
                }
            }
        }
        Ok(())
    });
    set.spawn(signal::ctrl_c());
    if set.join_next().await.is_some() {
        println!("Shutting down");
        set.shutdown().await;
    }
    Ok(())
}
